#!/bin/bash

# Matrix Framework Keycloak 初始化脚本
# 版本: 1.0
# 描述: 初始化 Keycloak Realm、客户端和用户

set -e

# 颜色定义
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color

# 日志函数
log_info() {
    echo -e "${BLUE}[INFO]${NC} $1"
}

log_success() {
    echo -e "${GREEN}[SUCCESS]${NC} $1"
}

log_warning() {
    echo -e "${YELLOW}[WARNING]${NC} $1"
}

log_error() {
    echo -e "${RED}[ERROR]${NC} $1"
}

# 从环境变量获取配置
KEYCLOAK_URL="${KEYCLOAK_URL:-http://localhost:8080}"
KEYCLOAK_ADMIN="${KEYCLOAK_ADMIN:-matrix_admin}"
KEYCLOAK_ADMIN_PASSWORD="${KEYCLOAK_ADMIN_PASSWORD:-Keycloak@2024}"
REALM_NAME="${REALM_NAME:-matrix}"

# 获取访问令牌
get_access_token() {
    log_info "获取 Keycloak 管理员访问令牌..."

    token_response=$(curl -s -X POST "${KEYCLOAK_URL}/realms/master/protocol/openid-connect/token" \
        -H "Content-Type: application/x-www-form-urlencoded" \
        -d "username=${KEYCLOAK_ADMIN}" \
        -d "password=${KEYCLOAK_ADMIN_PASSWORD}" \
        -d "grant_type=password" \
        -d "client_id=admin-cli")

    if [ $? -ne 0 ]; then
        log_error "无法获取访问令牌，请检查 Keycloak 服务状态和管理员凭据"
        exit 1
    fi

    access_token=$(echo $token_response | jq -r '.access_token')
    if [ "$access_token" = "null" ]; then
        log_error "访问令牌获取失败: $(echo $token_response | jq -r '.error_description // "未知错误"')"
        exit 1
    fi

    log_success "访问令牌获取成功"
    echo "$access_token"
}

# 检查 Realm 是否存在
check_realm_exists() {
    local token=$1
    local realm_name=$2

    log_info "检查 Realm '$realm_name' 是否存在..."

    response=$(curl -s -w "%{http_code}" -o /tmp/realm_check.json \
        -H "Authorization: Bearer $token" \
        "${KEYCLOAK_URL}/admin/realms/$realm_name")

    if [ "$response" = "200" ]; then
        log_success "Realm '$realm_name' 已存在"
        return 0
    elif [ "$response" = "404" ]; then
        log_info "Realm '$realm_name' 不存在，将创建"
        return 1
    else
        log_error "检查 Realm 时发生错误: HTTP $response"
        cat /tmp/realm_check.json
        exit 1
    fi
}

# 创建 Realm
create_realm() {
    local token=$1
    local realm_name=$2

    log_info "创建 Realm: $realm_name"

    realm_config=$(cat <<EOF
{
  "realm": "$realm_name",
  "enabled": true,
  "displayName": "Matrix Framework",
  "displayNameHtml": "<div class=\"kc-logo-text\"><span>Matrix Framework</span></div>",
  "registrationAllowed": true,
  "loginWithEmailAllowed": true,
  "duplicateEmailsAllowed": false,
  "resetPasswordAllowed": true,
  "editUsernameAllowed": true,
  "bruteForceProtected": true,
  "permanentLockout": false,
  "maxFailureWaitSeconds": 900,
  "minimumQuickLoginWaitSeconds": 60,
  "waitIncrementSeconds": 60,
  "quickLoginCheckMilliSeconds": 1000,
  "maxDeltaTimeSeconds": 43200,
  "failureFactor": 30,
  "bruteForceMaxLoginFailures": 5,
  "bruteForceMaxFailureWaitSeconds": 300,
  "maxDeltaTimeSeconds": 43200,
  "minimumQuickLoginWaitSeconds": 60,
  "tokenSignatureAlgorithm": "RS256",
  "revokeRefreshToken": false,
  "refreshTokenMaxReuse": 0,
  "accessTokenLifespan": 3600,
  "accessTokenLifespanForImplicitFlow": 900,
  "ssoSessionIdleTimeout": 1800,
  "ssoSessionMaxLifespan": 36000,
  "ssoSessionIdleTimeoutRememberMe": 0,
  "ssoSessionMaxLifespanRememberMe": 0,
  "offlineSessionIdleTimeout": 2592000,
  "offlineSessionMaxLifespanEnabled": false,
  "offlineSessionMaxLifespan": 5184000,
  "clientSessionIdleTimeout": 0,
  "clientSessionMaxLifespan": 0,
  "clientOfflineSessionIdleTimeout": 0,
  "clientOfflineSessionMaxLifespan": 0,
  "accessCodeLifespan": 60,
  "accessCodeLifespanUserAction": 300,
  "actionTokenGeneratedByAdminLifespan": 43200,
  "actionTokenGeneratedByUserLifespan": 300,
  "oauth2DeviceCodeLifespan": 600,
  "oauth2DevicePollingInterval": 5,
  "enabledEventTypes": [
    "LOGIN",
    "LOGIN_ERROR",
    "LOGOUT",
    "UPDATE_PASSWORD",
    "UPDATE_TOTP",
    "VERIFY_EMAIL",
    "REVOKE_GRANT",
    "CLIENT_LOGIN",
    "CLIENT_INITIATED_ACCOUNT_LINKING",
    "RESET_PASSWORD",
    "IMPERSONATE",
    "CUSTOM_REQUIRED_ACTION",
    "USER_INFO_REQUEST",
    "IDENTITY_PROVIDER_LINK_ACCOUNT",
    "IDENTITY_PROVIDER_UNLINK_ACCOUNT",
    "PERMISSION_TOKEN",
    "OAUTH2_DEVICE_AUTH_GRANT",
    "CLIENT_DELETE",
    "FEDERATED_IDENTITY_LINK"
  ],
  "browserSecurityHeaders": {
    "contentSecurityPolicyReportOnly": "frame-src 'self'; frame-ancestors 'self'; object-src 'none';",
    "xContentTypeOptions": "nosniff",
    "xRobotsTag": "none",
    "xFrameOptions": "SAMEORIGIN",
    "contentSecurityPolicy": "frame-src 'self'; frame-ancestors 'self'; object-src 'none';",
    "xXSSProtection": "1; mode=block",
    "strictTransportSecurity": "max-age=31536000; includeSubDomains"
  },
  "webAuthnPolicyRpEntityName": "Matrix Framework",
  "webAuthnPolicySignatureAlgorithms": [
    "ES256",
    "RS256",
    "ES384",
    "ES512",
    "PS256",
    "PS384",
    "PS512",
    "EdDSA"
  ],
  "webAuthnPolicyRpId": "",
  "webAuthnPolicyAttestationConveyancePreference": "not specified",
  "webAuthnPolicyAuthenticatorAttachment": "not specified",
  "webAuthnPolicyRequireResidentKey": "not specified",
  "webAuthnPolicyUserVerificationRequirement": "not specified",
  "webAuthnPolicyCreateTimeout": 0,
  "webAuthnPolicyAvoidSameAuthenticatorRegister": false,
  "webAuthnPolicyAcceptableAaguids": [],
  "attributes": {
    "cibaBackchannelTokenDeliveryMode": "poll",
    "cibaExpiresIn": 120,
    "cibaAuthRequestedUserHint": "login_hint",
    "oauth2DeviceAuthorizationGrantEnabled": true,
    "cibaInterval": 5,
    "realmOverrideEnabled": false,
    "clientOfflineSessionMaxLifespan": "0",
    "clientSessionIdleTimeout": "0",
    "clientOfflineSessionIdleTimeout": "0",
    "parRequestUriLifespan": 60,
    "frontChannelLogoutEnabled": false,
    "clientSessionMaxLifespan": "0",
    "oauth2DevicePollingInterval": "5"
  }
}
EOF
)

    response=$(curl -s -w "%{http_code}" -o /tmp/realm_create.json \
        -X POST "${KEYCLOAK_URL}/admin/realms" \
        -H "Authorization: Bearer $token" \
        -H "Content-Type: application/json" \
        -d "$realm_config")

    if [ "$response" = "201" ]; then
        log_success "Realm '$realm_name' 创建成功"
        return 0
    else
        log_error "Realm 创建失败: HTTP $response"
        cat /tmp/realm_create.json
        return 1
    fi
}

# 创建客户端
create_client() {
    local token=$1
    local realm_name=$2
    local client_id=$3
    local client_name=$4

    log_info "创建客户端: $client_id"

    client_config=$(cat <<EOF
{
  "clientId": "$client_id",
  "name": "$client_name",
  "description": "Matrix Framework $client_name",
  "enabled": true,
  "clientAuthenticatorType": "client-secret",
  "secret": "$(openssl rand -base64 32 | tr -d "=+/" | cut -c1-32)",
  "redirectUris": [
    "http://localhost/*",
    "http://localhost:3000/*",
    "http://localhost:3001/*"
  ],
  "webOrigins": [
    "http://localhost",
    "http://localhost:3000",
    "http://localhost:3001"
  ],
  "adminUrl": "",
  "rootUrl": "",
  "baseUrl": "",
  "bearerOnly": false,
  "publicClient": false,
  "standardFlowEnabled": true,
  "implicitFlowEnabled": false,
  "directAccessGrantsEnabled": true,
  "serviceAccountsEnabled": true,
  "authorizationServicesEnabled": false,
  "authorizationFlowEnabled": false,
  "directGrantsOnly": false,
  "fullScopeAllowed": true,
  "nodeReRegistrationTimeout": -1,
  "protocolMappers": [
    {
      "id": "1",
      "name": "tenant-id",
      "protocol": "openid-connect",
      "protocolMapper": "oidc-audience-mapper",
      "consentRequired": false,
      "config": {
        "included-client-audience": "matrix-management",
        "id.token.claim": "false",
        "access.token.claim": "true"
      }
    },
    {
      "id": "2",
      "name": "roles",
      "protocol": "openid-connect",
      "protocolMapper": "oidc-usermodel-client-role-mapper",
      "consentRequired": false,
      "config": {
        "multivalued": "true",
        "userinfo.token.claim": "true",
        "id.token.claim": "true",
        "access.token.claim": "true",
        "claim.name": "roles",
        "jsonType.label": "String"
      }
    },
    {
      "id": "3",
      "name": "permissions",
      "protocol": "openid-connect",
      "protocolMapper": "oidc-usermodel-realm-role-mapper",
      "consentRequired": false,
      "config": {
        "multivalued": "true",
        "userinfo.token.claim": "true",
        "id.token.claim": "true",
        "access.token.claim": "true",
        "claim.name": "permissions",
        "jsonType.label": "String"
      }
    }
  ]
}
EOF
)

    response=$(curl -s -w "%{http_code}" -o /tmp/client_create.json \
        -X POST "${KEYCLOAK_URL}/admin/realms/$realm_name/clients" \
        -H "Authorization: Bearer $token" \
        -H "Content-Type: application/json" \
        -d "$client_config")

    if [ "$response" = "201" ]; then
        log_success "客户端 '$client_id' 创建成功"
        return 0
    else
        log_error "客户端创建失败: HTTP $response"
        cat /tmp/client_create.json
        return 1
    fi
}

# 创建角色
create_role() {
    local token=$1
    local realm_name=$2
    local role_name=$3
    local role_description=$4

    log_info "创建角色: $role_name"

    role_config=$(cat <<EOF
{
  "name": "$role_name",
  "description": "$role_description",
  "composite": false,
  "clientRole": false,
  "containerId": "$realm_name",
  "attributes": {}
}
EOF
)

    response=$(curl -s -w "%{http_code}" -o /tmp/role_create.json \
        -X POST "${KEYCLOAK_URL}/admin/realms/$realm_name/roles" \
        -H "Authorization: Bearer $token" \
        -H "Content-Type: application/json" \
        -d "$role_config")

    if [ "$response" = "201" ]; then
        log_success "角色 '$role_name' 创建成功"
        return 0
    else
        log_warning "角色创建可能失败或已存在: HTTP $response"
        cat /tmp/role_create.json
        return 0  # 角色可能已存在，不视为错误
    fi
}

# 创建用户
create_user() {
    local token=$1
    local realm_name=$2
    local username=$3
    local email=$4
    local first_name=$5
    local last_name=$6
    local password=$7
    local roles=$8

    log_info "创建用户: $username"

    user_config=$(cat <<EOF
{
  "username": "$username",
  "email": "$email",
  "firstName": "$first_name",
  "lastName": "$last_name",
  "enabled": true,
  "emailVerified": true,
  "credentials": [
    {
      "type": "password",
      "value": "$password",
      "temporary": false
    }
  ],
  "attributes": {
    "locale": ["zh-CN"],
    "timezone": ["Asia/Shanghai"]
  }
}
EOF
)

    response=$(curl -s -w "%{http_code}" -o /tmp/user_create.json \
        -X POST "${KEYCLOAK_URL}/admin/realms/$realm_name/users" \
        -H "Authorization: Bearer $token" \
        -H "Content-Type: application/json" \
        -d "$user_config")

    if [ "$response" = "201" ]; then
        log_success "用户 '$username' 创建成功"

        # 获取用户 ID
        sleep 2
        user_id=$(curl -s -H "Authorization: Bearer $token" \
            "${KEYCLOAK_URL}/admin/realms/$realm_name/users?username=$username" | jq -r '.[0].id')

        # 分配角色
        if [ -n "$roles" ] && [ "$user_id" != "null" ]; then
            for role in $roles; do
                log_info "为用户 '$username' 分配角色: $role"
                curl -s -X POST "${KEYCLOAK_URL}/admin/realms/$realm_name/users/$user_id/role-mappings/realm" \
                    -H "Authorization: Bearer $token" \
                    -H "Content-Type: application/json" \
                    -d '[{"name":"'$role'"}]'
            done
        fi

        return 0
    else
        log_warning "用户创建可能失败或已存在: HTTP $response"
        cat /tmp/user_create.json
        return 0  # 用户可能已存在，不视为错误
    fi
}

# 主初始化函数
initialize_keycloak() {
    log_info "开始初始化 Keycloak..."

    # 等待 Keycloak 完全启动
    log_info "等待 Keycloak 服务完全启动..."
    max_attempts=30
    attempt=1

    while [ $attempt -le $max_attempts ]; do
        if curl -f "${KEYCLOAK_URL}/health" &> /dev/null; then
            break
        fi

        if [ $attempt -eq $max_attempts ]; then
            log_error "Keycloak 服务启动超时"
            exit 1
        fi

        log_info "等待 Keycloak 启动... ($attempt/$max_attempts)"
        sleep 10
        ((attempt++))
    done

    # 获取访问令牌
    access_token=$(get_access_token)

    # 检查或创建 Realm
    if ! check_realm_exists "$access_token" "$REALM_NAME"; then
        create_realm "$access_token" "$REALM_NAME"
    fi

    # 创建客户端
    create_client "$access_token" "$REALM_NAME" "matrix-admin" "Matrix Framework 管理后台"
    create_client "$access_token" "$REALM_NAME" "matrix-api" "Matrix Framework API"
    create_client "$access_token" "$REALM_NAME" "matrix-web" "Matrix Framework Web 应用"

    # 创建角色
    create_role "$access_token" "$REALM_NAME" "super-admin" "超级管理员"
    create_role "$access_token" "$REALM_NAME" "tenant-admin" "租户管理员"
    create_role "$access_token" "$REALM_NAME" "user-manager" "用户管理员"
    create_role "$access_token" "$REALM_NAME" "photo-manager" "相册管理员"
    create_role "$access_token" "$REALM_NAME" "engineering-manager" "工程管理员"
    create_role "$access_token" "$REALM_NAME" "user" "普通用户"

    # 创建初始用户
    create_user "$access_token" "$REALM_NAME" "superadmin" "superadmin@matrix.local" "超级" "管理员" "Admin@12345" "super-admin"
    create_user "$access_token" "$REALM_NAME" "admin" "admin@matrix.local" "系统" "管理员" "Admin@12345" "tenant-admin"
    create_user "$access_token" "$REALM_NAME" "usermanager" "usermanager@matrix.local" "用户" "管理员" "Admin@12345" "user-manager"
    create_user "$access_token" "$REALM_NAME" "testuser" "testuser@matrix.local" "测试" "用户" "User@12345" "user"

    # 清理临时文件
    rm -f /tmp/realm_*.json /tmp/client_*.json /tmp/role_*.json /tmp/user_*.json

    log_success "Keycloak 初始化完成！"
    echo ""
    echo "=================================="
    echo "🎉 Keycloak 初始化信息"
    echo "=================================="
    echo "🌐 Realm 名称:         $REALM_NAME"
    echo "🔑 管理员用户:         superadmin / Admin@12345"
    echo "👤 系统管理员:         admin / Admin@12345"
    echo "👥 用户管理员:         usermanager / Admin@12345"
    echo "🧪 测试用户:           testuser / User@12345"
    echo ""
    echo "📋 已创建的角色:"
    echo "  • super-admin        - 超级管理员"
    echo "  • tenant-admin       - 租户管理员"
    echo "  • user-manager       - 用户管理员"
    echo "  • photo-manager      - 相册管理员"
    echo "  • engineering-manager - 工程管理员"
    echo "  • user               - 普通用户"
    echo ""
    echo "🔗 已创建的客户端:"
    echo "  • matrix-admin       - 管理后台"
    echo "  • matrix-api         - API 服务"
    echo "  • matrix-web         - Web 应用"
}

# 主函数
main() {
    echo "=================================="
    echo "🔐 Keycloak 初始化脚本"
    echo "=================================="
    echo ""

    # 检查依赖
    if ! command -v curl &> /dev/null; then
        log_error "curl 命令未找到，请安装 curl"
        exit 1
    fi

    if ! command -v jq &> /dev/null; then
        log_error "jq 命令未找到，请安装 jq"
        exit 1
    fi

    # 检查参数
    if [ "$1" = "--help" ] || [ "$1" = "-h" ]; then
        echo "用法: $0 [选项]"
        echo ""
        echo "选项:"
        echo "  --help, -h          显示帮助信息"
        echo "  --url URL           Keycloak 服务 URL (默认: http://localhost:8080)"
        echo "  --realm REALM       Realm 名称 (默认: matrix)"
        echo "  --admin-user USER   管理员用户名 (默认: matrix_admin)"
        echo "  --admin-pass PASS   管理员密码"
        echo ""
        exit 0
    fi

    # 解析参数
    while [[ $# -gt 0 ]]; do
        case $1 in
            --url)
                KEYCLOAK_URL="$2"
                shift 2
                ;;
            --realm)
                REALM_NAME="$2"
                shift 2
                ;;
            --admin-user)
                KEYCLOAK_ADMIN="$2"
                shift 2
                ;;
            --admin-pass)
                KEYCLOAK_ADMIN_PASSWORD="$2"
                shift 2
                ;;
            *)
                log_warning "未知参数: $1"
                shift
                ;;
        esac
    done

    # 执行初始化
    initialize_keycloak
}

# 错误处理
trap 'log_error "Keycloak 初始化过程中发生错误"; exit 1' ERR

# 执行主函数
main "$@"